package com.beikai.redisdemo.service.impl;

import com.beikai.redisdemo.model.User;
import com.beikai.redisdemo.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : hanbeikai
 * Date: 2021/5/3 10:45 下午
 * Description: No Description
 */
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    private static Map<Long, User> userMap = new HashMap<>();

    static {
        userMap.put(1L, new User("肖战", 1L, 25));
        userMap.put(2L, new User("王一博", 2L, 26));
        userMap.put(3L, new User("杨紫", 3L, 24));
    }

    /**
     * @param user
     * @return
     * @CachePut 根据方法的请求参数对其结果进行缓存，和 @Cacheable 不同的是，它每次都会触发真实方法的调用。参数描述见上。
     */
    @CachePut(value = "user", key = "#user.id")
    @Override
    public User save(User user) {
        userMap.put(user.getId(), user);
        log.info("进入save方法，当前存储对象：{}", user.toString());
        return user;
    }

    /**
     * @param id
     * @CacheEvict 根据条件对缓存进行清空：
     * Key：同上。
     * Value：同上。
     * Condition：同上。
     * allEntries：是否清空所有缓存内容，缺省为 false，如果指定为 true，则方法调用后将立即清空所有缓存。
     * beforeInvocation：是否在方法执行前就清空，缺省为 false，如果指定为 true，则在方法还没有执行的时候就清空缓存。缺省情况下，如果方法执行抛出异常，则不会清空缓存。
     */
    @CacheEvict(value = "user", key = "#id", beforeInvocation = true)
    @Override
    public void delete(Long id) {
        userMap.remove(id);
        log.info("进入delete方法，删除成功");
    }

    /**
     * @param id
     * @return
     * @Cacheable 根据方法的请求参数对其结果进行缓存：
     * Key：缓存的 Key，可以为空，如果指定要按照 SPEL 表达式编写，如果不指定，则按照方法的所有参数进行组合。
     * Value：缓存的名称，必须指定至少一个（如 @Cacheable (value='user')或者 @Cacheable(value={'user1','user2'})）
     * Condition：缓存的条件，可以为空，使用 SPEL 编写，返回 true 或者 false，只有为 true 才进行缓存。
     */
    @Cacheable(value = "user", key = "#id")
    @Override
    public User get(Long id) {

        log.info("进入get方法，当前获取对象：{}", userMap.get(id) == null ? null : userMap.get(id).toString());
        return userMap.get(id);
    }

    @Override
    public Boolean testTrans() {

        try {
            Class<ConcurrentHashMap> concurrentHashMapClass = ConcurrentHashMap.class;
            Method resizeStamp = concurrentHashMapClass.getDeclaredMethod("resizeStamp", int.class);
            resizeStamp.setAccessible(true);
            Object invoke = resizeStamp.invoke(concurrentHashMapClass, 1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


        return null;
    }

    private void testDemo(){
        RedissonClient redissonClient = Redisson.create(new Config());
        RLock zhangsan = redissonClient.getLock("zhangsan");
        zhangsan.lock();
        zhangsan.unlock();
    }


}
